package os.t4;

import java.util.concurrent.Semaphore;

/**
 * 用信号量机制实现生产者消费者问题
 * Semaphore--信号
 * 信号量机制
 * - 信号量为正值：当前可利用的空闲资源数量
 * - 信号量为负值：表示系统中等待使用资源的进程数量
 * 首先消费者问题是同步加互斥问题
 * 同步是指：只有当生产者生产了物品，缓冲区不空时，消费者才可取；而消费者取走了物品，缓冲区又空了一位，生产者可获取的资源又增加
 * 因而同步暗含者线程的运行顺序，如生产者肯定在消费者进程之前运行
 * 故定义full:消费者同步资源信号量  empty:生产者同步资源信号量 两者的变化应该是联动的，full和empty起始描述的都是缓冲区资源
 * 对于消费者一开始缓冲区为空，可取出的物品为0，所以full初值=0
 * 而对于生产者一开始缓冲区为空，可以生产的物品为n，所以empty=n
 * 互斥：对于一个缓冲区同一时刻应该只允许生产者或者消费者访问，两个不同同时访问缓冲区
 * 故定义一个mutex初值为1
 * - p操作：申请一个单位的资源
 * - v操作：释放一个单位的资源
 * P操作：
 * ①将信号量S的值减1，即S=S-1；
 * ②如果S<=0，则该进程继续执行；否则该进程置为等待状态，排入等待队列。
 * V操作：
 * ①将信号量S的值加1，即S=S+1；
 * ②如果S>0，则该进程继续执行；否则释放队列中第一个等待信号量的进程。
 *
 * Semaphore是JDK提供的一个同步工具，
 * 它通过维护若干个许可证来控制线程对共享资源的访问。
 * 如果许可证剩余数量大于零时，线程则允许访问该共享资源；如果许可证剩余数量为零时，则拒绝线程访问该共享资源。
 * 线程通过调用
 * - acquire()获取许可证，相当于P操作
 * 执行完成之后通过调用
 * - release()归还许可证，相当于V操作
 * 只有获取到许可证的线程才能运行，获取不到许可证的线程将会阻塞。
 */
public class Resources {
    private static int n=5;//缓冲区大小
    static Semaphore mutex=new Semaphore(1);//互斥信号量,意为只有一个缓冲区
    static Semaphore full=new Semaphore(0);//消费者同步资源信号量,起始数组（缓冲区）数组为空,消费者阻塞
    static Semaphore empty=new Semaphore(n);//生产者同步资源信号量,起始数组（缓冲区）数组为空,可生产的空间为n,生产者激活
    static int[] arr=new int[n];//用数组充当缓冲区
    static int index=0;//控制数组下标移动
    public void product() throws InterruptedException {
        do{
            empty.acquire();//先做同步申请空闲缓冲区,生产一个产品生产者资源量减1
            mutex.acquire();//再做互斥，防止同一时刻生产者和消费者同时访问缓冲区

            //生产
            arr[index]= (int) (Math.random()*10+1);
            index++;
            System.out.println("生产者生产了"+arr[index-1]+"    此时index="+(index-1));

            mutex.release();
            full.release();//生产一个产品消费者资源量加1
            Thread.sleep(500);
        }while (true);
    }
    public void consume() throws InterruptedException {
        do{
            full.acquire();//一开始肯定阻塞，因为初始full=0,还没有产品可取
            mutex.acquire();//再做互斥，防止同一时刻生产者和消费者同时访问缓冲区

            //消费
            int temp=arr[index-1];
            index--;
            System.out.println("消费者消费了"+temp+"  此时index="+(index+1));

            mutex.release();
            empty.release();//消耗一个产品生产者资源量加1
            Thread.sleep(1000);
        }while (true);
    }
}
